import React from 'react';

export default () => {
  // 1. 兼容性结构子类型
  {
    interface Named {
      name: string;
    }

    class Person {
      name: string = "";
    }

    let p: Named;
    // OK, because of structural typing
    p = new Person();
  }
  // 2. 兼容性
  {
    interface Named {
      name: string;
    }

    let x: Named;
    let y = { name: 'Alice', location: 'Seattle' };
    x = y;

    function greet(n: Named) {
      console.log('Hello, ' + n.name);
    }
    greet(y); // OK 只有目标类型（这里是Named）的成员会被一一检查是否兼容
  }
  // 3. 函数兼容-参数
  {
    let x = (a: number) => 0;
    let y = (b: number, s: string) => 0;

    y = x; // OK
    // x = y; // Error
  }
  // 4. 函数兼容-返回类型
  {
    let x = () => ({name: 'Alice'});
    let y = () => ({name: 'Alice', location: 'Seattle'});

    x = y; // OK
    // y = x; // Error, because x() lacks a location property
  }
  // 5. 可选参数及剩余参数
  {
    function invokeLater(args: any[], callback: (...args: any[]) => void) {
      /* ... Invoke callback with 'args' ... */
    }

  // Unsound - invokeLater "might" provide any number of arguments
    invokeLater([1, 2], (x, y) => console.log(x + ', ' + y));

  // Confusing (x and y are actually required) and undiscoverable
    invokeLater([1, 2], (x?, y?) => console.log(x + ', ' + y));
  }
  return (
    <div>
      <h1>类型兼容性</h1>
      <p>1. TypeScript里的类型兼容性是基于结构子类型的。 结构类型是一种只使用其成员来描述类型的方式。 它正好与名义（nominal）类型形成对比。</p>
      <p>2. 如果x要兼容y，那么y至少具有与x相同的属性。</p>
      <p>3. 判断两个函数是否兼容-参数：相反，看被赋予方是否满足所有参数，并不允许忽略。</p>
      <p>4. 判断两个函数是否兼容-返回类型：类型系统强制源函数的返回值类型必须是目标函数返回值类型的子类型。</p>
      <p>5. 可选参数与必须参数是可互换的。 源类型上有额外的可选参数不是错误，目标类型的可选参数在源类型里没有对应的参数也不是错误。</p>
      <p>6. 类，只有实例的成员会被比较。 静态成员和构造函数不在比较的范围内。私有成员和受保护成员只允许子类赋值给父类，不能赋值其他同样类型的类</p>
    </div>
  );
};
